use crate::errors::Result;
use crate::models::*;
use crate::services::article_service::ArticleService;
use crate::services::product_service::ProductService;
use crate::services::category_service::CategoryService;
use crate::services::brand_service::BrandService;
use crate::services::language_service::LanguageService;
use actix_web::{get, web, HttpResponse};
use actix_web::web::Query;
use sea_orm::DatabaseConnection;
use utoipa::path;
use uuid::Uuid;

#[utoipa::path(
    get,
    path = "/public/articles",
    tag = "Public Articles",
    operation_id = "get_published_articles",
    params(
        ("category_id" = Option<Uuid>, Query, description = "Filter by category ID"),
        ("keyword" = Option<String>, Query, description = "Search keyword"),
        ("language_code" = Option<String>, Query, description = "Language code"),
        ("page" = Option<u32>, Query, description = "Page number"),
        ("per_page" = Option<u32>, Query, description = "Items per page")
    ),
    responses(
        (status = 200, description = "Articles retrieved successfully", body = PaginatedResponse<Article>),
        (status = 400, description = "Invalid request")
    )
)]
#[get("/articles")]
pub async fn get_articles(
    db: web::Data<DatabaseConnection>,
    query: Query<FilterOptions>,
) -> Result<HttpResponse> {
    let options = query.into_inner();
    let articles = ArticleService::list_published(&db, options).await?;
    Ok(HttpResponse::Ok().json(articles))
}

#[utoipa::path(
    get,
    path = "/public/articles/{id}",
    tag = "Public Articles",
    operation_id = "get_article_by_id",
    params(
        ("id" = Uuid, Path, description = "Article ID"),
        ("language_code" = Option<String>, Query, description = "Language code")
    ),
    responses(
        (status = 200, description = "Article retrieved successfully", body = Article),
        (status = 404, description = "Article not found")
    )
)]
#[get("/articles/{id}")]
pub async fn get_article(
    db: web::Data<DatabaseConnection>,
    path: web::Path<Uuid>,
    query: Query<FilterOptions>,
) -> Result<HttpResponse> {
    let id = path.into_inner();
    let query_options = query.into_inner();
    let language_code = query_options.language_code.as_deref();
    
    let article = ArticleService::get_published_by_id(&db, id, language_code).await?;
    Ok(HttpResponse::Ok().json(article))
}

#[utoipa::path(
    get,
    path = "/public/products",
    tag = "Public Products",
    operation_id = "get_published_products",
    params(
        ("category_id" = Option<Uuid>, Query, description = "Filter by category ID"),
        ("brand_id" = Option<Uuid>, Query, description = "Filter by brand ID"),
        ("keyword" = Option<String>, Query, description = "Search keyword"),
        ("language_code" = Option<String>, Query, description = "Language code"),
        ("page" = Option<u32>, Query, description = "Page number"),
        ("per_page" = Option<u32>, Query, description = "Items per page")
    ),
    responses(
        (status = 200, description = "Products retrieved successfully", body = PaginatedResponse<Product>),
        (status = 400, description = "Invalid request")
    )
)]
#[get("/products")]
pub async fn get_products(
    db: web::Data<DatabaseConnection>,
    query: Query<FilterOptions>,
) -> Result<HttpResponse> {
    let options = query.into_inner();
    let products = ProductService::list_published(&db, options).await?;
    Ok(HttpResponse::Ok().json(products))
}

#[utoipa::path(
    get,
    path = "/public/products/{id}",
    tag = "Public Products",
    operation_id = "get_product_by_id",
    params(
        ("id" = Uuid, Path, description = "Product ID"),
        ("language_code" = Option<String>, Query, description = "Language code")
    ),
    responses(
        (status = 200, description = "Product retrieved successfully", body = Product),
        (status = 404, description = "Product not found")
    )
)]
#[get("/products/{id}")]
pub async fn get_product(
    db: web::Data<DatabaseConnection>,
    path: web::Path<Uuid>,
    query: Query<FilterOptions>,
) -> Result<HttpResponse> {
    let id = path.into_inner();
    let query_options = query.into_inner();
    let language_code = query_options.language_code.as_deref();
    
    let product = ProductService::get_published_by_id(&db, id, language_code).await?;
    Ok(HttpResponse::Ok().json(product))
}

#[utoipa::path(
    get,
    path = "/public/categories",
    tag = "Public Categories",
    operation_id = "get_categories",
    params(
        ("language_code" = Option<String>, Query, description = "Language code")
    ),
    responses(
        (status = 200, description = "Categories retrieved successfully", body = Vec<Category>),
        (status = 400, description = "Invalid request")
    )
)]
#[get("/categories")]
pub async fn get_categories(
    db: web::Data<DatabaseConnection>,
    query: Query<FilterOptions>,
) -> Result<HttpResponse> {
    let query_options = query.into_inner();
    let language_code = query_options.language_code.as_deref();
    let categories = CategoryService::list_active(&db, language_code).await?;
    Ok(HttpResponse::Ok().json(categories))
}

#[utoipa::path(
    get,
    path = "/public/brands",
    tag = "Public Brands",
    operation_id = "get_brands",
    params(
        ("language_code" = Option<String>, Query, description = "Language code")
    ),
    responses(
        (status = 200, description = "Brands retrieved successfully", body = Vec<Brand>),
        (status = 400, description = "Invalid request")
    )
)]
#[get("/brands")]
pub async fn get_brands(
    db: web::Data<DatabaseConnection>,
    query: Query<FilterOptions>,
) -> Result<HttpResponse> {
    let query_options = query.into_inner();
    let language_code = query_options.language_code.as_deref();
    let brands = BrandService::list_active(&db, language_code).await?;
    Ok(HttpResponse::Ok().json(brands))
}

#[utoipa::path(
    get,
    path = "/public/languages",
    tag = "Public Languages",
    operation_id = "get_active_languages",
    responses(
        (status = 200, description = "Languages retrieved successfully", body = Vec<Language>),
        (status = 400, description = "Invalid request")
    )
)]
#[get("/languages")]
pub async fn get_languages(
    db: web::Data<DatabaseConnection>,
) -> Result<HttpResponse> {
    let languages = LanguageService::get_active_languages(&db).await?;
    Ok(HttpResponse::Ok().json(languages))
}